package fr.cephb.joperon.webapp;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.oreilly.servlet.MultipartRequest;
import com.sleepycat.db.DatabaseException;

import fr.cephb.joperon.core.Mode;
import fr.cephb.joperon.core.Operon;
import fr.cephb.joperon.core.Ymd;
import fr.cephb.joperon.core.bio.Assembly;
import fr.cephb.joperon.core.bio.Organism;
import fr.cephb.joperon.core.db.PrjMgrDB;
import fr.cephb.joperon.core.entities.MPanel;
import fr.cephb.joperon.core.entities.PrjFin;
import fr.cephb.joperon.core.entities.PrjMgr;
import fr.cephb.joperon.core.iterator.AbstractIterator;
import fr.cephb.joperon.tool.OperonFactory;
import fr.cephb.joperon.tool.createprj.CreatePrjFin;
import fr.cephb.joperon.webapp.jpa.Access;
import fr.cephb.joperon.webapp.jpa.User;
import fr.cephb.util.C;
import fr.cephb.util.Cast;

public class GWTControler extends AbstractOperonServlet
	{
	private static final long serialVersionUID = 1L;
	private static final String JSON_MIME="application/json";
	
	
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException
		{
		String pathInfo= req.getPathInfo();
		if(pathInfo==null || !pathInfo.startsWith("/"))
			{
			res.sendError(HttpServletResponse.SC_NOT_FOUND);
			return;
			}
		pathInfo = pathInfo.substring(1);
		int i= pathInfo.indexOf('/');
		if(i!=-1) pathInfo=pathInfo.substring(0,i);
		if( pathInfo.equals("service") ||
			pathInfo.equals("doGet") ||
			pathInfo.equals("doPost")
			)
			{
			res.sendError(HttpServletResponse.SC_NOT_FOUND);
			return;
			}
		Method m =null;
		try {
			m = getClass().getMethod(pathInfo,
					HttpServletRequest.class,
					HttpServletResponse.class,
					OperonFactory.class
					);
			}
		catch (Exception e)
			{
			res.sendError(HttpServletResponse.SC_NOT_FOUND,"unknown service "+pathInfo);
			return;
			}
		debug(pathInfo);
		Operon operon=null;
		OperonFactory factory=null;
		try {
			operon= Operon.newInstance(super.getDBHome());
			factory = new OperonFactory(operon);
			m.invoke(this, req,res,factory);
			}
		catch (Exception err)
			{
			throw new ServletException(err);
			}
		finally
			{
			if(factory!=null) factory.close();
			if(operon!=null) operon.safeClose();
			}
		}
	
	
	public void ping(HttpServletRequest req, HttpServletResponse res,OperonFactory factory) throws ServletException, IOException
		{
		boolean success=true;
		if(!"POST".equalsIgnoreCase(req.getMethod()))
			{
			success=false;
			}
		
		String login =  req.getParameter("login");
		if(success && login==null)
			{
			success=false;
			}
		else
			{
			HttpSession session= req.getSession(false);
			if(session==null)
				{
				success=false;
				}
			else
				{
				User user= (User)session.getAttribute("operon_user");
				if(user==null || !login.equals(user.getLogin()))
					{
					success=false;
					}
				}
			}
		PrintWriter out= res.getWriter();
		out.print("{status:200,message:" +
				success+
				"}");
		out.flush();
		}
	

	/** 
	 * log to operon
	 */
	public void login(HttpServletRequest req, HttpServletResponse res,OperonFactory factory) throws ServletException, IOException
		{
		if(!"POST".equalsIgnoreCase(req.getMethod()))
			{
			res.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
			return;
			}
		
		String login =  req.getParameter("login");
		String password =  req.getParameter("password");
		
		if(isEmpty(login) || password==null)
			{
			debug("cannot empty ="+login+"="+password+"=");
			error(res,HttpServletResponse.SC_UNAUTHORIZED,"empty login/password");
			return;
			}
		
		User user= getUserByLoginPassword(login, password);
		if(user==null)
			{
			debug("cannot login");
			error(res,HttpServletResponse.SC_UNAUTHORIZED,"Wrong login/password");
			return;
			}
		HttpSession session= req.getSession();
		if(session==null)
			{
			debug("cannot create session");
			error(res,HttpServletResponse.SC_UNAUTHORIZED,"cannot create session");
			return;
			}
		session.setAttribute("operon_user", user);
		
		res.setContentType(JSON_MIME);
		PrintWriter out= res.getWriter();
		out.print("{status:200,message:\"OK\"," +
				"login:"+quote(user.getLogin())+","+
				"admin:"+ user.isAdministrator()+","+
				"anonymous:"+ user.isAnonymous()+","+
				"JSESSIONID:"+ quote(session.getId())+"" +
				"}");
		out.flush();
		}
	
	public void test(HttpServletRequest req, HttpServletResponse res,OperonFactory factory) throws ServletException, IOException
		{
		res.setContentType(JSON_MIME);
		HttpSession session= req.getSession();
		PrintWriter out= res.getWriter();
		out.print("{status:200,message:\"OK\",JSESSIONID:"+ quote(session.getId())+
				",newsession:"+ session.isNew() 
				+"}");
		out.flush();
		}
	
	private static String quote(String s)
		{
		if(s==null) return "null";
		return "\""+C.escape(s)+"\"";
		}
	
	private static void print(PrintWriter out,Assembly as)
	{
	if(as==null) { out.print("null"); return;}
		
	out.print("{id:"+as.getId()+
			",taxid:"+as.getTaxId()+
			",code:"+quote( as.getShortCode())+
			",source:"+quote(as.getSource())+
			",version:"+quote(as.getVersion())+
			",name:"+quote(as.getName())+
			",organism:");print(out,as.getOrganism());
	out.print("}");
	}
	
	private static void print(PrintWriter out,Organism org)
		{
		out.print("{id:"+org.getOperonId()+
				",taxid:"+org.getTaxId()+
				",code:"+quote( org.getTreeLetterCode())+
				",name:"+quote(org.getName())+
				"}"
				);
		}
	
	private static void print(PrintWriter out,PrjMgr prj)
	{
	out.print("{pid:"+quote(prj.getPid())+
			",def:"+quote(prj.getDef())+
			",log:"+quote(prj.getLog())+
			",ymd:"+quote(prj.getYmd())+
			"}"
			);
	}
	
	private static void print(PrintWriter out,PrjFin prjfin)
		{
		out.print("{pid:"+quote(prjfin.getPid())+
				",def:"+quote(prjfin.getDef())+
				",log:"+quote(prjfin.getLog())+
				",ymd:"+quote(prjfin.getYmd())+
				",fix:"+quote(prjfin.getFix())+
				",projCode:"+quote(prjfin.getProjCode())+
				",assembly:");
		print(out,prjfin.getAssembly());
		out.print("}");
		}
	
	
	private static void print(PrintWriter out,MPanel mpanel)
		{
		out.print("{acn:"+quote(mpanel.getAcn())+
				",def:"+quote(mpanel.getDef())+
				",syn:"+quote(mpanel.getSyn())+
				",uid:"+mpanel.getUid()+
				"}"
				);
		}
	
	/** create a new project. user must be admin */
	public void createproject(HttpServletRequest req, HttpServletResponse res,OperonFactory factory)
	throws ServletException, IOException,DatabaseException
		{
		User user= getUser(req);
		if(user==null || user.isAnonymous())
			{
			error(res,HttpServletResponse.SC_UNAUTHORIZED,"UNAUTHORIZED");
			return;
			}

		String pid= req.getParameter("pid");
		if(pid==null) pid="";
		pid=pid.trim().toUpperCase();
		
		String def= req.getParameter("def");
		if(def==null) def="";
		def=def.trim();
	
		debug("\n\npid"+pid+" def:"+def+" method:"+req.getMethod());
		

		if(isEmpty(pid) || isEmpty(def) || !"POST".equals(req.getMethod()))
			{
			error(res,HttpServletResponse.SC_BAD_REQUEST,"BAD_REQUEST check pid/def/method");
			return;
			}
		
		
		if(factory.getPrjMgr().containsKey(pid))
			{
			error(res,HttpServletResponse.SC_NOT_ACCEPTABLE,"pid already exists");
			return;
			}
		
		
		factory.close();
		PrjMgr mgr= new PrjMgr();
		mgr.setDef(def);
		mgr.setLog(user.getLogin());
		mgr.setPid(pid);
		mgr.setYmd(Ymd.now());
		
		Operon writer=null;
		PrjMgrDB db=null;
		try {
			writer=  Operon.newInstance(getDBHome(),Mode.WRITE);
			db= new PrjMgrDB(writer);
			db.open();
			db.put(mgr.getPid(), mgr);
			
			
			getUserTransaction().begin();
			try {
				Access access= new Access();
				access.setUser(user);
				access.setProject(pid);
				access.setAdministrator(true);
				access.setWriter(true);
				getTopLink().persist(access);
				getUserTransaction().commit();
				} 
			catch (Exception e)
				{
				//cannot rollback berkeley
				debug(e);
				e.printStackTrace();
				}
			
			res.setContentType(JSON_MIME);
			PrintWriter out= res.getWriter();
			out.print("{status:200,message:{prjmgr:");
			print(out,mgr);
			out.print("}}");
			out.flush();
			} 
		catch (Exception e) 
			{
			debug(e.getMessage());
			error(res,HttpServletResponse.SC_INTERNAL_SERVER_ERROR,e.getMessage());
			}
		finally
			{
			if(db!=null) db.safeClose();
			if(writer!=null) writer.safeClose();
			}
		}
	
	private void printAssemblies(PrintWriter out)
		{
		boolean found=false;
		out.print("[");
		for( Assembly as:Assembly.getAssemblies())
			{
			if(found) out.print(',');
			found=true;
			print(out,as);
			}
		out.print("]");
		}
	
	public void assemblies(HttpServletRequest req, HttpServletResponse res,OperonFactory factory) throws ServletException, IOException
		{
		res.setContentType(JSON_MIME);
		PrintWriter out= res.getWriter();
		out.print("{status:200,message:");
		printAssemblies(out);
		out.print("}");
		out.flush();
		}
	
	/* get the projects visible by this user */
	public void projects(HttpServletRequest req, HttpServletResponse res,OperonFactory factory)
		throws ServletException, IOException,DatabaseException
		{
		User user= getUser(req);
		if(user==null)
			{
			error(res,HttpServletResponse.SC_UNAUTHORIZED,"UNAUTHORIZED");
			return;
			}
		res.setContentType(JSON_MIME);
		PrintWriter out= res.getWriter();
		boolean found=false;
		out.print("{status:200,message:{table:[");
		PrjMgrDB.ValueIterator iter=null;
		
		try {
			iter= factory.getPrjMgr().listValues();
			while(iter.hasNext())
				{
				PrjMgr p= iter.next();
				//log("found project "+p+" public:"+p.isPublic());
				if(!p.isPublic())
					{
					if(p.isAdmin() && !user.isAdministrator())
						{
						continue;
						}
					if(!user.canReadProject(p.getPid()))
						{
						continue;
						}
					}
				if(found) out.print(",");
				found=true;
				print(out,p);
				}
			out.print("]}}");
			out.flush();
			}
		catch (Exception e)
			{
			throw new DatabaseException(e);
			}
		finally
			{
			if(iter!=null) iter.close();
			}
		}
	
	public void mpanels(HttpServletRequest req, HttpServletResponse res,OperonFactory factory)
		throws ServletException, IOException,DatabaseException
		{
		User user= getUser(req);
		if(user==null)
			{
			error(res,HttpServletResponse.SC_UNAUTHORIZED,"UNAUTHORIZED:mpanels");
			return;
			}
		res.setContentType(JSON_MIME);
		PrintWriter out= res.getWriter();
		boolean found=false;
		out.print("{status:200,message:{mpanels:[");
		for(MPanel mpanel :factory.getMPanel().getValues())
			{
			if(found) out.print(",");
			found=true;
			print(out,mpanel);
			}
		out.print("]}}");
		}
	
	/* return the prjfin for the given target */
	public void prjfins(HttpServletRequest req, HttpServletResponse res,OperonFactory factory)
		throws ServletException, IOException,DatabaseException
		{
		User user= getUser(req);
		if(user==null)
			{
			error(res,HttpServletResponse.SC_UNAUTHORIZED,"UNAUTHORIZED");
			return;
			}
		String t= req.getParameter("target");
		if(t==null)
			{
			error(res,HttpServletResponse.SC_BAD_REQUEST,"BAD_REQUEST:target is null");
			return;
			}
		PrjFin.Target target=null;
		try {
			target= PrjFin.Target.valueOf(t);
		} catch (Exception e) {
			error(res,HttpServletResponse.SC_BAD_REQUEST,"BAD_REQUEST: bad target");
			return;
			}
		
		res.setContentType(JSON_MIME);
		PrintWriter out= res.getWriter();
		boolean found=false;
		out.print("{status:200,message:{prjfin:[");
		for(PrjFin prjfin:getPrjFinForUser(user, factory, target))
			{
			if(found) out.print(",");
			found=true;
			print(out,prjfin);
			}
		out.print("]}}");
		}
	
	public void aboutsnp(HttpServletRequest req, HttpServletResponse res,OperonFactory factory)
	throws ServletException, IOException,DatabaseException
		{
		User user= getUser(req);
		if(user==null)
			{
			res.sendError(HttpServletResponse.SC_UNAUTHORIZED);
			return;
			}
		
		if(req.getContentType()==null || !req.getContentType().contains("multipart/form-data"))
			{
			res.sendError(HttpServletResponse.SC_BAD_REQUEST);
			return;
			}
		MultipartRequest multipartRequest= new MultipartRequest(req,getWebTmpDir());
		
		
		super.runSnpInfo(multipartRequest, res, factory, user);
		}
	
	
	/** chqnge the status of a user in this project */
	public void adminprjmgr(HttpServletRequest req, HttpServletResponse res,OperonFactory factory)
		throws ServletException, IOException,DatabaseException
		{
		User user= getUser(req);
		if(user==null)
			{
			error(res,HttpServletResponse.SC_UNAUTHORIZED,null);
			return;
			}
		String pid= req.getParameter("pid");
		String userid= req.getParameter("user-id");
		String changes= req.getParameter("act");
		if(isEmpty(pid) ||
				isEmpty(changes) ||
				isEmpty(userid) || 
				!user.canAdminProject(pid) ||
				!"POST".equals(req.getMethod())
				)
			{
			error(res,HttpServletResponse.SC_BAD_REQUEST,"BAD_REQUEST pid/user-id/act");
			return;
			}
		
		User userToBeModified = getUserByLogin(userid);
		if(userToBeModified==null)
			{
			error(res,HttpServletResponse.SC_BAD_REQUEST,"BAD_REQUEST:user not found");
			return;
			}
		
		Access access = getAccessByUserPid(userToBeModified,pid);
		if(access==null)
			{
			error(res,HttpServletResponse.SC_BAD_REQUEST,"BAD_REQUEST/No access");
			return;
			}
		
		
		
		
		try {
			getUserTransaction().begin();
			try {
				if(changes.equals("prjmgr-user-admin"))
					{
					access.setAdministrator(true);
					access.setWriter(true);
					getTopLink().merge(access);
					}
				else if(changes.equals("prjmgr-user-writer"))
					{
					access.setAdministrator(false);
					access.setWriter(true);
					getTopLink().merge(access);
					}
				else if(changes.equals("prjmgr-user-read"))
					{
					access.setAdministrator(false);
					access.setWriter(false);
					getTopLink().merge(access);
					}
				else if(changes.equals("prjmgr-remove-user")
					&& user.getId()!=userToBeModified.getId()	
					)
					{
					getTopLink().remove(access);
					}
				getUserTransaction().commit();
				} 
			catch (Exception e)
				{
				debug(e);
				error(res,HttpServletResponse.SC_INTERNAL_SERVER_ERROR,e.getMessage());
				return;
				}
			error(res,HttpServletResponse.SC_OK,"OK");
			} 
		catch (Exception e) 
			{
			debug(e.getMessage());
			error(res,HttpServletResponse.SC_INTERNAL_SERVER_ERROR,e.getMessage());
			}
		}
	
	
	public void createuser(HttpServletRequest req, HttpServletResponse res,OperonFactory factory)
		throws ServletException, IOException,DatabaseException
			{
		
			User user= getUser(req);
			if(user==null || !user.isRoot())
				{
				error(res,HttpServletResponse.SC_UNAUTHORIZED,null);
				return;
				}
			
			String userid= req.getParameter("login");
			String password= req.getParameter("password");
			String admin= req.getParameter("admin");
			
			
			if(isEmpty(userid) || 
					password==null ||
					!"POST".equals(req.getMethod()))
				{
				error(res,HttpServletResponse.SC_BAD_REQUEST,"BAD_REQUEST user/login/password");
				return;
				}
			User userToBeInserted = getUserByLogin(userid);
			if(userToBeInserted!=null)
				{
				error(res,HttpServletResponse.SC_BAD_REQUEST,"BAD_REQUEST:user already exists");
				return;
				}
		
			
		
		try {
			getUserTransaction().begin();
			try {
				userToBeInserted= new User(userid);
				userToBeInserted.setSha1Password(sha1(password));
				if(admin!=null && admin.equals("true"))
					{
					userToBeInserted.setAdministrator(true);
					}
				
				getTopLink().persist(userToBeInserted);
				getUserTransaction().commit();
				} 
			catch (Exception e)
				{
				debug(e);
				getUserTransaction().rollback();
				error(res,HttpServletResponse.SC_INTERNAL_SERVER_ERROR,e.getMessage());
				return;
				}
			error(res,HttpServletResponse.SC_OK,"OK");
			} 
		catch (Exception e) 
			{
			debug(e);
			error(res,HttpServletResponse.SC_INTERNAL_SERVER_ERROR,e.getMessage());
			}
			
		}
	
	
	public void prjmgraddsnp(HttpServletRequest req, HttpServletResponse res,OperonFactory factory)
		throws ServletException, IOException,DatabaseException
		{
		User user= getUser(req);
		if(user==null)
			{
			res.sendError(HttpServletResponse.SC_UNAUTHORIZED);
			return;
			}
		
		if(req.getContentType()==null || !req.getContentType().contains("multipart/form-data"))
			{
			res.sendError(HttpServletResponse.SC_BAD_REQUEST);
			return;
			}
		MultipartRequest multipartRequest= new MultipartRequest(req,getWebTmpDir());
		
		CreatePrjFin subapp= new CreatePrjFin();
		subapp.setTarget(PrjFin.Target.SNP);
		subapp.setUser(user);
		
		File file=multipartRequest.getFile("file");
		if(file==null)
			{
			debug("no file");
			res.sendError(HttpServletResponse.SC_BAD_REQUEST);
			return;
			}
		subapp.setInputFile(file);
		
		String pid= multipartRequest.getParameter("project-id");
		if(isEmpty(pid))
			{
			debug("no pid");
			res.sendError(HttpServletResponse.SC_BAD_REQUEST);
			return;
			}
		subapp.setProjectId(pid);
		
		
		String def= multipartRequest.getParameter("def");
		if(isEmpty(def))
			{
			debug("no def");
			res.sendError(HttpServletResponse.SC_BAD_REQUEST);
			return;
			}
		subapp.setDef(def);
		
		String as= multipartRequest.getParameter("as");
		if(as==null || isEmpty(as) || !Cast.Integer.isA(as) ||
			Assembly.getAssemblyById(Cast.Integer.cast(as))==null)
			{
			debug("no as");
			res.sendError(HttpServletResponse.SC_BAD_REQUEST);
			return;
			}
		
		Assembly assembly = Assembly.getAssemblyById(Cast.Integer.cast(as));
		subapp.setAssembly(assembly);
		
		
		
		
			factory.close();
			Operon writer=null;
			OperonFactory wFact=null;
			try {
				writer=  Operon.newInstance(getDBHome(),Mode.WRITE);
				wFact= new OperonFactory(writer);
				subapp.setFactory(wFact);
				subapp.build();	
				res.sendError(HttpServletResponse.SC_OK);
				}
			catch (Exception e) 
				{
				debug(e);
				res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
				}
			finally
				{
				if(wFact!=null) wFact.close();
				if(writer!=null) writer.safeClose();
				file.delete();
				}
			
			}
	
	
	public void prjmgradduser(HttpServletRequest req, HttpServletResponse res,OperonFactory factory)
	throws ServletException, IOException,DatabaseException
		{
		debug();
		User user= getUser(req);
		if(user==null)
			{
			error(res,HttpServletResponse.SC_UNAUTHORIZED,null);
			return;
			}
		String pid= req.getParameter("pid");
		String userid= req.getParameter("user-id");
		if(isEmpty(pid) || isEmpty(userid) || 
				!user.canAdminProject(pid) ||
				!"POST".equals(req.getMethod()))
			{
			debug("boum");
			error(res,HttpServletResponse.SC_BAD_REQUEST,"BAD_REQUEST : pid:"+pid+" user-id:"+userid);
			return;
			}
		User userToBeInserted = getUserByLogin(userid);
		if(userToBeInserted==null)
			{
			error(res,HttpServletResponse.SC_BAD_REQUEST,"BAD_REQUEST:user not found");
			return;
			}
		
		debug(userToBeInserted);
		
		PrjMgr prjmgr=factory.getPrjMgr().get(pid);
		if(prjmgr==null)
			{
			error(res,HttpServletResponse.SC_BAD_REQUEST,"BAD_REQUEST:unknown pid");
			return;
			}
		
		if(userToBeInserted.canReadProject(pid))
			{
			debug("already know that user can read project");
			error(res,HttpServletResponse.SC_OK,"OK");
			return;
			}
		
		if(!user.canWriteProject(pid))
			{
			debug();
			error(res,HttpServletResponse.SC_UNAUTHORIZED,"Cannot admin this project");
			return;
			}
		
		
		
		
		try {
			getUserTransaction().begin();
			try {
				Access access= new Access();
				access.setUser(userToBeInserted);
				access.setProject(pid);
				access.setAdministrator(false);
				access.setWriter(false);
				getTopLink().persist(access);
				getUserTransaction().commit();
				} 
			catch (Exception e)
				{
				debug(e);
				error(res,HttpServletResponse.SC_INTERNAL_SERVER_ERROR,e.getMessage());
				return;
				}
			error(res,HttpServletResponse.SC_OK,"OK");
			} 
		catch (Exception e) 
			{
			debug(e.getMessage());
			error(res,HttpServletResponse.SC_INTERNAL_SERVER_ERROR,e.getMessage());
			}
		}

	/* return information about a given project */
	public void project(HttpServletRequest req, HttpServletResponse res,OperonFactory factory)
		throws ServletException, IOException,DatabaseException
		{
		User user= getUser(req);
		if(user==null)
			{
			error(res,HttpServletResponse.SC_UNAUTHORIZED,"UNAUTHORIZED");
			return;
			}
		
		String pid= req.getParameter("pid");
		if(isEmpty(pid))
			{
			error(res,HttpServletResponse.SC_BAD_REQUEST,"BAD_REQUEST pid");
			return;
			}
		PrjMgr project=factory.getPrjMgr().get(pid);
		
		if(project==null)
			{
			error(res,HttpServletResponse.SC_BAD_REQUEST,"BAD_REQUEST project cannot find "+pid);
			return;
			}
		
		if(!user.canReadProject(pid))
			{
			error(res,HttpServletResponse.SC_UNAUTHORIZED,"UNAUTHORIZED");
			return;
			}
		
		res.setContentType(JSON_MIME);
		PrintWriter out= res.getWriter();
		boolean found=false;
		out.print("{status:200,message:{project:");
		print(out,project);
		out.print(",users:[");
		for(Object o:getTopLink().createNamedQuery("access.users.byProject").setParameter("project", pid).getResultList())
			{
			User u= User.class.cast(o);
			if(found) out.print(",");
			found=true;
			out.print("{id:"+u.getId()+",login:"+quote(u.getLogin())+"}");
			}
		out.print("]");
		
		out.print(",assemblies:");
		printAssemblies(out);
	
		found=false;
		
		for(PrjFin.Target target : PrjFin.Target.values())
			{
			out.print(",prj"+target.name().toLowerCase()+":[");
			AbstractIterator<PrjFin> iter=null;
			
			found=false;
			try
				{
				iter=factory.getPrjFin().listProjectsByIdAndTarget(pid,target);
				while(iter.hasNext())
					{
					PrjFin prjfin=iter.next();
					if(found) out.print(",");
					found=true;
					print(out,prjfin);
					}
				out.print("]");
				}
			catch(DatabaseException err)
				{
				log("boum",err);
				res.resetBuffer();
				error(res,HttpServletResponse.SC_INTERNAL_SERVER_ERROR,err.getMessage());
				return;
				}
			finally
				{
				if(iter!=null) iter.close();
				}
			}
		out.print("}}");
		out.flush();
		
		}
	
	
	
	private User getUser(HttpServletRequest req)throws ServletException
		{
		HttpSession session= req.getSession(false);
		if(session==null) return null;
		return User.class.cast(session.getAttribute("operon_user"));
		}
	
	private void error(HttpServletResponse res,int code,String message) throws IOException
		{
		if(message==null) message= "ERROR";
		res.setContentType(JSON_MIME);
		PrintWriter out= res.getWriter();
		out.print("{status:"+code+",message:"+ quote(message)+"}");
		out.flush();
		}
	
	}
